﻿using DLL.MSDM.Entity;
using DLL.Net.DB.Recorder.CRUD.Service;
using DLL.Net.MS.Models;
using DLL.Net.RJSpeech;
using DLL.NET.Login.Account.Entity.DTO;
using DLL.NET50.DB.MS.AdviceAndDrug;
using DLL.NET50.DB.MS.AdviceAndDrug.ORM.Repository;
using DLL.NET50.DB.MS.AdviceAndDrug.ORM.Service;
using DLL.NET50.DB.MS.PIVASAndDicDrug.ORM;
using DLL.NET50.DB.PIVAS.ORM.Service;

using DLL.NET60.DB.MS.Entity.DTO;
using DLL.NET70.Infrastructure.Prism.EventAggregator;
using DLL.NetStandard.FlushRobot.MS.Entity.Param;
using DLL.Standard.Infrastructure.Entity;
using DLL.Standard.Infrastructure.Log;
using log4net.Core;
using Prism.Events;
using Prism.Services.Dialogs;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading;

namespace Module.AutoRun
{
    public interface IMS_ScanBar : IScanBarBase
    {
        public int TPFlushMode { get; set; }
        public int SurplusMode { get; set; }

        public int ProcessScanBar(string scanBar);

        public void InitializeAdvices();

        public void SendClearLablesMessage();
    }

    public class CMS_ScanBar : CScanBarBase, IMS_ScanBar
    {
        private CMS_AdviceAndDrugs advicesForFlush = new CMS_AdviceAndDrugs();
        public DTO_adi_dic_drug[] currentUsedDrugs = new DTO_adi_dic_drug[6];

        public float[] RemainDrugDose = new float[6] { 0, 0, 0, 0, 0, 0 };

        //统配模式
        private int _TPFlushMode = 0;

        public int TPFlushMode
        {
            get { return _TPFlushMode; }
            set { _TPFlushMode = value; }
        }

        private int _SurplusMode = 0;//结余模式

        public int SurplusMode
        {
            get => _SurplusMode;
            set { _SurplusMode = value; }
        }

        private CMS_WorkConfigParam _workConfig = new CMS_WorkConfigParam();//加工配置参数
        private CMS_DeviceConfigParam _deviceConfig = new CMS_DeviceConfigParam();//设备硬件参数

        // private CWorkPoints _workPoints = new CDSZWorkPoints();
        private CMS_HPScanBar sP_ScanBar;

        private IEventAggregator _eventAggregator;

        private IDialogService _dialogService;
        private IPIVASAndDicDrug _PIVASAndDicDrug;

        private IAdviceAndDicDrugsService _adviceAndDicDrugsService;
        private IAdviceExecuteService _PivasAdviceExcuteService;

        private adi_accountDTO _logAccount;

        public CMS_ScanBar(IEventAggregator eventAggregator,
            IAdviceExecuteService pivasAdviceExcuteService,
            IAdviceAndDicDrugsService adviceAndDicDrugsService,
            IPIVASAndDicDrug piVASAndDicDrug,
            IAdviceRecordService adviceRecordService,
            ISendLogMessage sendLogMessage,
            IDialogService dialogService,
            adi_accountDTO account) : base(eventAggregator,
                pivasAdviceExcuteService,
                adviceRecordService,
                sendLogMessage,
                account, dialogService)
        {
            _eventAggregator = eventAggregator;
            _logAccount = account;
            _adviceAndDicDrugsService = adviceAndDicDrugsService;
            _PIVASAndDicDrug = piVASAndDicDrug;
            _PivasAdviceExcuteService = pivasAdviceExcuteService;
            _dialogService = dialogService;
            sP_ScanBar = new CMS_HPScanBar();
            ReadParam();
            SetGetValidBarParam();
            InitializeVariable();
        }

        private void ReadParam()
        {
            CMS_WR_WorkConfigParam wrparam = new CMS_WR_WorkConfigParam();
            bool ret = wrparam.ReadParam();
            if (true == ret)
            {
                _workConfig = wrparam.Param;
            }
            CMS_WR_DeviceConfigParam wr_deviceConfig = new CMS_WR_DeviceConfigParam();
            wr_deviceConfig.ReadParam();
            _deviceConfig = wr_deviceConfig.Param;
            EnableJiFei = _workConfig.EnableJiFei;//启用和服务器对接，判断医嘱是否挺住
        }

        private void SetGetValidBarParam()
        {
            ValidBarParam.EnableProcessBar = _workConfig.EnableProcessBar;
            ValidBarParam.ProcessBarMethord = _workConfig.ProcessBarMethord;
            ValidBarParam.BarCharStartPos = _workConfig.BarCharStartPos;
            ValidBarParam.BarCharCount = _workConfig.BarCharCount;
            ValidBarParam.enableBatchDM = _workConfig.enableBatchDM;
            ValidBarParam.scanBarResultType = _workConfig.scanBarResultType;
        }

        #region Event

        //发送消息给配药机主界面
        private void ScanBar_SendMessage(CMS_AdvicesMsg msg)
        {
            _eventAggregator.GetEvent<CMS_AdvicesMsgEvent>().Publish(msg);
        }

        //发送刷新显示瓶贴消息
        private void ShowLabelsMsg(CMS_ShowLabelsMsg msg)
        {
            msg.ConnectMode = ConnectMode;
            _eventAggregator.GetEvent<CMS_ShowLabelsMsgEvent>().Publish(msg);
        }

        //发送停医嘱消息
        public override void SendAdviceStopMessage()
        {
            CMS_ShowLabelsMsg msg = new CMS_ShowLabelsMsg();
            msg.CommandStr = MSDM_CmdStr.AdviceStop;
            msg.LableID = GetNotUsedStationID();
            msg.value = adviceStopID.ToString();
            msg.ScanBar = ScanedBar;
            ShowLabelsMsg(msg);
        }

        //发送清空瓶贴消息
        public void SendClearLablesMessage()
        {
            CMS_ShowLabelsMsg msg = new CMS_ShowLabelsMsg();
            msg.CommandStr = MSDM_CmdStr.Clear;
            ShowLabelsMsg(msg);
        }

        //发送医嘱获取正常消息
        private void SendAdviceOKMessage(CMS_AdviceAndDrugs adviceAndDrugs)
        {
            CMS_AdvicesMsg msg = new CMS_AdvicesMsg();
            msg.CommandStr = MSDM_CmdStr.AdviceOK;
            msg.adviceAndDrugs = adviceAndDrugs;
            ScanBar_SendMessage(msg);

            CMS_ShowLabelsMsg msg1 = new CMS_ShowLabelsMsg();
            msg1.CommandStr = MSDM_CmdStr.AdviceOK;
            msg1.adviceAndDrugs = adviceAndDrugs;
            ShowLabelsMsg(msg1);
        }

        #endregion Event

        public override int ProcessScanBar(string scanBar)
        {
            int ret = 0;
            try
            {
                ret = LocalProcessBar(scanBar);
                if (0 == ret)
                {
                    LogMessage(ErrorInfo);
                }
            }
            catch (Exception e)
            {
                LogMessage(e.Message, LogLevel.Warning);
            }

            return ret;
        }

        private int LocalProcessBar(string scanBar)
        {
            try
            {
                //第一步，获取有效条码,用来解决，读取到的瓶贴号与扫描到的瓶贴号不一致
                string adviceNo = "";
                int ret = GetValidBar(scanBar, ref adviceNo);
                ScanedBar = adviceNo;
                if (0 == ret)
                { return 0; }

                //判断该条码是否已经扫描过
                if (AllHadScanedBar.ContainsKey(adviceNo))
                {
                    ErrorInfo = ("该条码已经扫描过");
                    return 0;
                }
                //判断是否已经扫描了6个条码
                if (-1 == GetNotUsedStationID())//ValidHadScanedBar.Count >= maxSolventCount
                {
                    ErrorInfo = ("当前批次扫码数量已满！");
                    return 0;
                }
                //判断有没有停医嘱,先判断是否停医嘱，用来解决，停药了，没有读取过来医嘱，会报错，本地不存在该医嘱
                string userCode = _logAccount.MJobNumber;
                ret = AdviceIsNotStop(adviceNo, userCode);
                if (1 != ret)
                {
                    //停药,或计费接口异常
                    return 0;
                }
                //判断条码有没有配过
                int canFlush = TheBarCanFlush(adviceNo);
                if (0 == canFlush)
                {
                    return 0;
                }
                //第二步，判断本地是否存在该药品
                ret = SetDrugProperty(adviceNo);
                if (0 == ret)
                {
                    return 0;
                }
                //第三步，获取医嘱和药品字典
                CMS_AdviceAndDrug adviceAndDrug = new CMS_AdviceAndDrug();
                ret = GetAdviceAndDrugFromDatabase(adviceNo, ref adviceAndDrug);
                if (0 == ret)
                {
                    return 0;
                }
                //
                ret = ProcessAdviceAndDrug(adviceAndDrug, adviceNo);
                if (0 == ret)
                {
                    return 0;
                }
            }
            catch (Exception e)
            {
                LogMsg.Warn("扫码出现异常：条码=" + scanBar + "异常信息=" + e.Message);
                return 0;
            }

            return 1;
        }

        public override int LocalHadThisAdvice(string scanBar)
        {
            try
            {
                int recount = 0;
                while (recount < 3)
                {
                    int count = _adviceAndDicDrugsService.GetAdviceCount(scanBar);
                    if (count == 0)
                    {
                        recount++;
                        Thread.Sleep(100);
                    }
                    else
                    {
                        return 1;
                    }
                }

                if (recount >= 3)
                {
                    ErrorInfo = ("PIVAS数据库不存在该医嘱=" + scanBar);
                    LogMsg.Warn(ErrorInfo);
                    return 0;
                }
            }
            catch (Exception e)
            {
                LogMsg.Warn("判断PIVAS数据库是否存在该医嘱出现异常：" + e.Message);
                return 0;
            }

            return 1;
        }

        public override int SetDrugProperty(string scanBar)
        {
            try
            {
                int drugCount = 0;
                //获取医嘱中，本地不存在的药品编码
                CDrugCodes drugCodes = _adviceAndDicDrugsService.GetLoacalNotExistDrugCodes(scanBar);
                if (drugCodes.reValue == 0)
                {
                    //根据瓶贴号，没有获取到药品编码
                    ErrorInfo = (drugCodes.reMsg);
                    drugCount = 0;
                    return 0;
                }
                else
                {
                    //本地存在该药品
                    //返回药品编码正常
                    drugCount = drugCodes.drugCodes.Count;
                    if (drugCount > 0)
                    {
                        //返回的是存在的医嘱
                        for (int i = 0; i < drugCount; i++)
                        {
                            string drugCode = drugCodes.drugCodes[i];
                            //弹出对话框
                            DTO_adi_dic_drug drug = _PIVASAndDicDrug.GetNewDrugByCode(drugCode);
                            if (drug.DRUG_CODE.Length == 0)
                            {
                                ErrorInfo = ("PIVAS数据库不存在该药品编码：" + drugCode);
                                return 0;
                            }
                            DialogParameters dialogParameters = new DialogParameters();
                            dialogParameters.Add("DrugCode", drug);
                            _dialogService.ShowDialog("PUC_DialogEditDrug", dialogParameters, AddDrugCallback, GlobalDialogNames.CustomDialogWindow);
                        }
                        //设置完所有药品的属性后，需要重新扫码！
                        ErrorInfo = ("设置完所有药品的属性后，需要重新扫码！");
                        return 0;
                    }
                    return 1;
                }
            }
            catch (Exception e)
            {
                LogMsg.Warn("设置药品属性出现异常：" + e.Message);
                return 0;
            }
        }

        private void AddDrugCallback(IDialogResult dialogResult)
        {
            if (dialogResult.Result == ButtonResult.Yes)
            {
                LogMessage("保存成功");
            }
            else
            {
                LogMessage("退出！");
            }
        }

        //根据瓶贴号，获取医嘱和药品
        private int GetAdviceAndDrugFromDatabase(string bar, ref CMS_AdviceAndDrug adviceAndDrug)
        {
            try
            {
                adviceAndDrug = _adviceAndDicDrugsService.GetAdviceAndDrug(bar);
                if (adviceAndDrug != null)
                {
                    if (adviceAndDrug.reValue == 1)
                    {
                        //添加判断返回的医嘱是有效的医嘱
                        adviceAndDrug.SurPlusMode = SurplusMode;
                        int ret = AdviceIsValid(adviceAndDrug);
                        if (0 == ret)
                        {
                            return 0;
                        }
                        int canUsedStationID = GetNotUsedStationID();
                        int drugChanged = DrugIsNotChanged(adviceAndDrug, canUsedStationID);
                        if (0 == drugChanged)
                        {
                            return 0;
                        }
                    }
                    else
                    {
                        ErrorInfo = adviceAndDrug.Info;
                        return 0;
                    }
                }
            }
            catch (Exception e)
            {
                LogMsg.Warn("获取医嘱和药品出现异常：" + e.Message);
                return 0;
            }

            return 1;
        }

        //判断药物有没有发生改变
        private int DrugIsNotChanged(CMS_AdviceAndDrug adviceAndDrug, int stationID)
        {
            try
            {
                //药品字典存在该药
                if (TPFlushMode == 1)
                {
                    if (SurplusMode == 1)
                    {
                        //结余模式：判断该医嘱是否满足结余模式
                        bool re = Surplus_AdviceIsValid(adviceAndDrug);
                        if (false == re)
                        {
                            //结余模式下，医嘱无效
                            return 0;
                        }
                    }
                    string drugName = TP_GetFirstDrugName();
                    //统配模式，所有的药，和第一个药做对比，来判断药品是否改变
                    if (drugName != null)
                    {
                        //没有保存记录的药，则药品没有改变
                        if (drugName.Length != 0)
                        {
                            //说明已经配过药
                            if (drugName != adviceAndDrug.Drugs[0].DRUG_NAME.Trim())
                            {
                                //说明药发生改变
                                ErrorInfo = "药发生改变，不能在一起配药，记录的条码名称=" + drugName + "当前扫描的条码:" + adviceAndDrug.Drugs[0].DRUG_NAME.Trim();
                                return 0;//医嘱无效
                            }
                        }
                    }
                }
                else
                {
                    //混配模式
                    //1.如果没有记录配的药，则该医嘱有效，记录该药品，不需要和其他药品做
                    bool adviceIsValid = sP_ScanBar.SP_CanDispenseMedicinesTogether(adviceAndDrug, stationID, ref currentUsedDrugs);
                    if (false == adviceIsValid)
                    {
                        ErrorInfo = "不能混配:" + sP_ScanBar.ErrMsg;
                        return 0;//医嘱无效
                    }
                }
                //判断该站台是不是已经保存了药
                int isRecorded = HadRecordDrug(stationID);
                if (0 == isRecorded)
                {
                    //没有保存药
                    currentUsedDrugsName[stationID] = adviceAndDrug.Drugs[0].DRUG_NAME.Trim();
                    currentUsedSolventName[stationID] = adviceAndDrug.Solvent.DRUG_NAME.Trim();
                }
            }
            catch (Exception e)
            {
                LogMsg.Warn("判断药品是否发生改变出现异常：" + e.Message);
                return 0;
            }

            return 1;
        }

        private string TP_GetFirstDrugName()
        {
            for (int i = 0; i < 6; i++)
            {
                if (CanUsedLabelStation[i] == 1)
                {
                    return currentUsedDrugsName[i];
                }
            }
            return "";
        }

        private int HadRecordDrug(int stationID)
        {
            if (currentUsedDrugsName[stationID] != null)
            {
                if (currentUsedDrugsName[stationID].Length != 0)
                {
                    return 1;//已经有保存的药
                }
                else
                {
                    return 0;
                }
            }

            return 0;//还没有记录在配的药
        }

        //结余模式下，判断医嘱是否有效
        private bool Surplus_AdviceIsValid(CMS_AdviceAndDrug adviceAndDrug)
        {
            try
            {
                //当前是结余模式，只有在基于的模式下，才会判断医嘱是否适合结余模式
                int drugCount = adviceAndDrug.GetDrugCount();
                if (drugCount != 1)
                {
                    ErrorInfo = ("当前医嘱，药瓶数量大于1只药，不能用于结余模式！");
                    return false;
                }
                //添加判断剩余量是否够当前医嘱使用
                int adviceCount = advicesForFlush.adviceAndDrugs.Count();
                double currentAdviceRealDose = Convert.ToDouble(adviceAndDrug.adviceDrug[0].REALDOSE);
                if (adviceCount == 0)
                {
                    adviceCount = 1;
                }
                double remainDose = RemainDrugDose[adviceCount - 1];
                if (remainDose > 0)
                {
                    //西林瓶内有剩余剂量
                    if (remainDose < currentAdviceRealDose)
                    {
                        //西林瓶内的剩余剂量不够当前医嘱
                        ErrorInfo = ("当前医嘱实际使用剂量大于西林瓶内的剩余剂量，该医嘱无法配药，请扫描其它医嘱或点击放药！");
                        return false;
                    }
                }
            }
            catch (Exception e)
            {
                LogMsg.Warn("判断医嘱是否满足结余模式出现异常：" + e.Message);
                return false;
            }

            return true;
        }

        //判断医嘱是不是有效的医嘱，主要判断，剂量，数量，和实际使用的剂量的关系
        private int AdviceIsValid(CMS_AdviceAndDrug adviceAndDrug)
        {
            try
            {
                //添加判断医嘱是否正常
                if ((0 == adviceAndDrug.adviceDrug.Count))
                {
                    ErrorInfo = "药品属性设置错误，医嘱里面只有溶媒没有药！";
                    return 0;
                }
                float dose = adviceAndDrug.adviceDrug[0].DOSE;
                float realDose = adviceAndDrug.adviceDrug[0].REALDOSE;
                int quantity = Convert.ToInt32(adviceAndDrug.adviceDrug[0].QUANTITY);
                int count1 = Convert.ToInt32(Math.Ceiling(realDose / dose));
                if (count1 != quantity)
                {
                    //医嘱无效
                    //ErrorInfo = "无效医嘱，医嘱剂量=" + dose.ToString() + ";实际剂量=" + realDose.ToString() + ";数量=" + quantity.ToString();
                    //return 0;//医嘱无效
                }
                if ((dose * quantity) != realDose)
                {
                    CRJSpeech.SpeakAsync("该医嘱是非整支，请注意！");
                }
            }
            catch (Exception e)
            {
                LogMsg.Warn("判断医嘱是否有效出现异常：" + e.Message);
                return 0;
            }

            return 1;
        }

        //保存医嘱到数据库
        private void SaveAdviceToRecorder(CMS_AdviceAndDrug adviceAndDrug)
        {
            try
            {
                //adviceAndDrug.AdviceHadStop = 0;
                //保存医嘱到记录recorder数据库
                RecorderService.Add(adviceAndDrug.pivasAdvicePatient);
                RecorderService.Add(adviceAndDrug.pivasAdviceDrugs);
                RecorderService.AddScanBar(adviceAndDrug.pivasAdvicePatient.ADVICE_GROUP_NO,
                adviceAndDrug.Drugs[0].DRUG_CODE,
                _logAccount.MJobNumber,
                adviceAndDrug.Drugs[0].DRUG_NAME,
                adviceAndDrug.GetDrugCount());
            }
            catch (Exception ex)
            {
                LogMsg.Warn("保存医嘱到数据库出现异常！" + ex.Message);
            }
        }

        private List<string> GetDrugCodes(CMS_AdviceAndDrug adviceAndDrug)
        {
            List<string> drugCodes = new List<string>();
            return drugCodes;
        }

        private int ProcessAdviceAndDrug(CMS_AdviceAndDrug adviceAndDrug, string bar)
        {
            try
            {
                if (adviceAndDrug == null)
                {
                    return 0;
                }
                if (adviceAndDrug.reValue == 1)
                {
                    AllHadScanedBar[bar] = bar;
                    AddAdvice(adviceAndDrug, bar);
                    SaveAdviceToRecorder(adviceAndDrug);
                    SendAdviceOKMessage(advicesForFlush);
                }
                else
                {
                    //医嘱获取失败
                    ErrorInfo = (adviceAndDrug.Info);
                    //添加刷新瓶贴显示界面
                    adviceAndDrug.AdviceHadStop = -1;
                    return 0;
                }
            }
            catch (Exception e)
            {
                LogMsg.Warn("添加医嘱出现异常：" + e.Message);
                return 0;
            }

            return 1;
        }

        //将医嘱加入配药序列
        private void AddAdvice(CMS_AdviceAndDrug advice, string adviceNo)
        {
            int noAdviceStationID = GetNotUsedStationID();
            if (-1 == noAdviceStationID)
            {
                return;
            }
            ValidHadScanedBar[noAdviceStationID] = adviceNo;
            advice.ScanBarTime = DateTime.Now;
            advice.Enable = 1;
            advice.AdviceHadStop = 0;
            advicesForFlush.adviceAndDrugs[noAdviceStationID] = advice;
        }

        //记录已经扫描的药品
        private void RecordScanDrug(CMS_AdviceAndDrug adviceAndDrug, int colID)
        {
            int HaveAdviceCount = colID;
            if (1 == TPFlushMode)
            {
                //统配,之和第一站的药品做比较
                if (currentUsedDrugs[colID].SOLVENT_FLAG == null)
                {
                    currentUsedDrugs[colID] = adviceAndDrug.Drugs[0];
                }
                //每一个注射器对应一个溶媒，以后扫到的溶媒之和使用过的溶媒做比较
                if (currentUsedSolventName[HaveAdviceCount] == null)
                {
                    currentUsedSolventName[HaveAdviceCount] = adviceAndDrug.Solvent.DRUG_NAME.Trim();
                }
            }
            else
            {
                //混配模式
                if (currentUsedSolventName[HaveAdviceCount] == null)
                {
                    currentUsedSolventName[HaveAdviceCount] = adviceAndDrug.Solvent.DRUG_NAME.Trim();
                }
            }
        }

        //清空医嘱
        public override void InitializeVariable()
        {
            LogMessage("清空医嘱！");
            base.InitializeVariable();
            InitializeAdvices();//初始化医嘱
        }

        public void InitializeAdvices()
        {
            AllHadScanedBar.Clear();
            advicesForFlush.adviceAndDrugs.Clear();
            for (int i = 0; i < 6; i++)
            {
                CMS_AdviceAndDrug adviceAndDrug = new CMS_AdviceAndDrug();
                adviceAndDrug.Enable = 0;
                if (0 == CanUsedLabelStation[i])
                {
                    //这个占位没有启用
                    ValidHadScanedBar[i] = "0";
                }
                else
                {
                    ValidHadScanedBar[i] = "1";
                }
                advicesForFlush.adviceAndDrugs.Add(adviceAndDrug);
            }
        }

        public override void InitializeCurrentUsedDrug()
        {
            for (int i = 0; i < 6; i++)
            {
                currentUsedDrugs[i] = new DTO_adi_dic_drug();
            }
            base.InitializeCurrentUsedDrug();
        }
    }
}